// Class include
#include "CWatchdog.hpp"

// System includes
#include <unistd.h>     // For sleep
#include <sys/timeb.h>

// Other includes
#include "CTrace.hpp"
#include "Types.hpp"

// Forward declaration inckudes
#include "CCommand.hpp"

CWatchdog* CWatchdog::mSelf = 0;

CWatchdog::CWatchdog()
: CObserver()
, mpSerialReader(0)
, mLastOnlineEventTime(getMilliCount())
{
}

CWatchdog::~CWatchdog()
{
}

void CWatchdog::handleEvent(const CCommand& cmd)
{
   if (COMMAND_ARDUINO_ONLINE == cmd.getType())
   {
      TRC_DEBUG("Watchdog: watchdog reset");
      mLastOnlineEventTime = getMilliCount();
   }
}

CWatchdog* CWatchdog::getInstance()
{
   if (mSelf == 0)
   {
      mSelf = new CWatchdog();
   }

   return mSelf;
}

int CWatchdog::getMilliCount()
{
    timeb tb;
    ftime(&tb);
    int nCount = tb.millitm + (tb.time & 0xfffff) * 1000;
    return nCount;
}
int CWatchdog::getMilliSpan(int nTimeStart)
{
    int nSpan = getMilliCount() - nTimeStart;
    if(nSpan < 0)
        nSpan += 0x100000 * 1000;
    return nSpan;
}

void CWatchdog::setSerialReaderPointer(CSerialReader* pSerialReader)
{
   mpSerialReader = pSerialReader;
}

void CWatchdog::start()
{
   do
   {
      TRC_DEBUG("Watchdog: new iteration");

      int currentTime = getMilliCount();

      if (getMilliSpan(mLastOnlineEventTime) > WATCHDOG_TIMEOUT_MS)
      {
         // Watchdog should restart Arduino!!!
         if (0 != mpSerialReader)
         {
            TRC_WARNING("Watchdog: reconnecting to Arduino");
            mpSerialReader->initSerialPort();
         }
         else
         {
            TRC_ERROR("Watchdog: mpSerialReader pointer is NULL");
         }
      }
      else
      {
         TRC_DEBUG("Watchdog: currentTime = %d, lastOnlineEventTime=%d, diff = %d", currentTime, mLastOnlineEventTime, currentTime-mLastOnlineEventTime);
      }

      usleep(1000 * WATCHDOG_TIMEOUT_MS);
   } while(true);
}